/*
 * Copyright (c) 2025 GuoKaiHong (Shenzhen) Technology Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <cstdio>
#include <aki/jsbind.h>
#include <string>
#include <cstring>
#include "stdio.h"
#include <usb/usb_ddk_api.h>
#include <usb/usb_ddk_types.h>
#include <usb/usb_ddk_types.h>
#include "gkhos_log.h"
int g_cmd;
int g_readLen;

// 定义一个只读的unsigned char类型的二维数组write_buf
// 该数组用于存储一系列固定长度的数据帧，每个数据帧长度为10个字节
// 数据帧的结构和内容可能代表特定的命令、配置或数据包，发送到某个设备或用于某个特定的通信协议
const unsigned char WRITE_BUF[][10] = {{0xAA, 0xAA, 0xAA, 0x96, 0x69, 0x00, 0x03, 0x10, 0xff, 0xec},
                                       {0xAA, 0xAA, 0xAA, 0x96, 0x69, 0x00, 0x03, 0x11, 0xff, 0xed},
                                       {0xAA, 0xAA, 0xAA, 0x96, 0x69, 0x00, 0x03, 0x12, 0xff, 0xee},
                                       {0xAA, 0xAA, 0xAA, 0x96, 0x69, 0x00, 0x03, 0x20, 0x01, 0x22},
                                       {0xAA, 0xAA, 0xAA, 0x96, 0x69, 0x00, 0x03, 0x20, 0x02, 0x21},
                                       {0xAA, 0xAA, 0xAA, 0x96, 0x69, 0x00, 0x03, 0x30, 0x01, 0x32},
                                       {0xAA, 0xAA, 0xAA, 0x96, 0x69, 0x00, 0x03, 0x30, 0x03, 0x30}};

// 定义一个常量二维数组SW，用于存储特定的状态字节映射
const unsigned char SW[][4] = {
    {0x00, 0x00, 0x90, 0x01}, {0x00, 0x00, 0x9f, 0x01}, {0x00, 0x00, 0x10, 0xff}, {0x00, 0x00, 0x11, 0xff},
    {0x00, 0x00, 0x21, 0xff}, {0x00, 0x00, 0x24, 0xff}, {0xff, 0xff, 0x31, 0xff}, {0x00, 0x00, 0x32, 0xff},
    {0x00, 0x00, 0x33, 0xff}, {0x00, 0x00, 0x40, 0xff}, {0xff, 0xff, 0x41, 0xff}, {0xff, 0xff, 0x47, 0xff},
    {0x00, 0x00, 0x60, 0xff}, {0x00, 0x00, 0x66, 0xff}, {0x00, 0x00, 0x80, 0x00}, {0xff, 0xff, 0x81, 0x00},
    {0x00, 0x00, 0x91, 0xff},

};


#define TX_ORDER_NUM 7
#define RX_STATES_NUM 17

#define CMD_SEARCH 4
#define CMD_SELECT 5
#define CMD_INFO 6

#define BULK_ENDPOINT_OUT 0x1
#define BULK_ENDPOINT_IN 0x81

static int g_deviceId;
static struct UsbDeviceDescriptor devDesc;

static uint64_t g_devHandle = 0;
uint64_t g_interfaceHandle = 0;
uint8_t g_dataEp = 0;
uint8_t g_dataEpin = 0;
uint8_t g_interface = 0;
uint16_t g_maxPktSize = 0;

unsigned char g_readBuf[2048] = {0};

// 定义USB端点属性常量
#define ENDPOINT_ADDRESS_SHIFT_BITS 7          // 端点地址位移位数
#define ENDPOINT_DIRECTION_MASK 1              // 端点方向掩码
#define ENDPOINT_TYPE_MASK 0x03                // 端点类型掩码
#define ENDPOINT_TYPE_BULK 0x02                // 批量传输类型
#define ENDPOINT_TYPE_INTERRUPT 0x03           // 中断传输类型

bool IsOutEp(const UsbEndpointDescriptor& epDesc)
{
    return (((epDesc.bEndpointAddress >> ENDPOINT_ADDRESS_SHIFT_BITS) & ENDPOINT_DIRECTION_MASK) == 0) &&
           ((epDesc.bmAttributes & ENDPOINT_TYPE_MASK) == ENDPOINT_TYPE_BULK);
}


/**
 * 查找指定接口的端点信息
 * @param intDesc 接口描述符
 * @param numSetting 备用设置数量
 * @return 如果找到合适的端点，返回包含接口和端点信息的元组；否则返回默认值
 */
static std::tuple<bool, uint8_t, uint8_t, uint16_t> FindEndpointInInterface(
    struct UsbDdkInterfaceDescriptor *intDesc, uint32_t numSetting)
{
    // 定义常量以避免魔法数字
    const uint32_t maxAltSettings = 256;      // 最大备用设置数
    const uint32_t maxEndpoints = 16;          // 最大端点数
    
    // 限制备用设置数量以防止异常情况
    if (numSetting > maxAltSettings) {
        numSetting = maxAltSettings;
    }
    
    // 遍历当前接口的所有备用设置
    for (uint32_t setIdx = 0; setIdx < numSetting; ++setIdx) {
        uint32_t numEp = intDesc[setIdx].interfaceDescriptor.bNumEndpoints;
        
        // 限制端点数量以防止异常情况
        if (numEp > maxEndpoints) {
            numEp = maxEndpoints;
        }
        
        struct UsbDdkEndpointDescriptor *epDesc = intDesc[setIdx].endPoint;
        
        // 遍历当前备用设置的所有端点
        for (uint32_t epIdx = 0; epIdx < numEp; ++epIdx) {
            // 检查当前端点是否为块传输输出端点
            if (!IsOutEp(epDesc[epIdx].endpointDescriptor)) {
                continue;
            }
            
            LOG("bInterfaceNumber: %{public}u\n", intDesc[setIdx].interfaceDescriptor.bInterfaceClass);
            // 返回找到的接口和端点信息
            return {true, intDesc[setIdx].interfaceDescriptor.bInterfaceNumber,
                    epDesc[epIdx].endpointDescriptor.bEndpointAddress,
                    epDesc[epIdx].endpointDescriptor.wMaxPacketSize};
        }
    }
    
    // 如果未找到合适的端点，返回默认值
    return {false, {}, {}, {}};
}

/**
 * GetInterfaceAndEndpoint 根据USB配置描述符获取特定接口和端点信息。
 * @param config 指向UsbDdkConfigDescriptor结构的指针，包含USB设备的配置信息。
 * @param in 指示是否查找输入端点，未在代码中使用。
 * @return 返回一个包含接口和端点信息的结构体，如果未找到合适的端点，则返回{false, {}, {}, {}}。
 * 此函数遍历USB配置描述符中的所有接口和端点，寻找符合特定条件的端点。
 * 它检查每个接口的每个备用设置，并遍历这些设置中的端点，以找到符合IS_BULK_OUT_EP宏定义的端点。
 * 找到合适的端点后，它将返回接口编号、端点地址和最大包大小等信息。
 */
// 获取手写板的接口和端点
static std::tuple<bool, uint8_t, uint8_t, uint16_t> GetInterfaceAndEndpoint(
    const struct UsbDdkConfigDescriptor *config, bool in)
{
    // 定义常量以避免魔法数字
    const uint32_t maxInterfaces = 256;        // 最大接口数
    
    // 检查配置描述符是否有效
    if (config == nullptr) {
        return {false, {}, {}, {}};
    }
    uint32_t numInterfaces = config->configDescriptor.bNumInterfaces;
    // 限制接口数量以防止异常情况
    if (numInterfaces > maxInterfaces) {
        numInterfaces = maxInterfaces;
    }
    // 遍历所有接口
    for (uint32_t intIdx = 0; intIdx < numInterfaces; ++intIdx) {
        struct UsbDdkInterfaceDescriptor *intDesc = config->interface[intIdx].altsetting;
        uint32_t numSetting = config->interface[intIdx].numAltsetting;
        // 在当前接口中查找端点
        auto result = FindEndpointInInterface(intDesc, numSetting);
        // 如果找到了合适的端点，直接返回结果
        if (std::get<0>(result)) {
            return result;
        }
    }
    // 如果未找到合适的端点，返回默认值
    return {false, {}, {}, {}};
}


/**
 * 将BCD码转换为ASCII码字符串
 * BCD码（Binary-Coded Decimal）是一种用二进制编码十进制数字的方式
 * 这个函数接收一个表示BCD码的字节序列，将其转换为对应的ASCII码字符串表示
 * @param bcd 指向BCD码的指针，每个字节代表一个BCD码
 * @param len BCD码的长度，即字节数
 * @return 返回一个动态分配的字符数组，包含转换后的ASCII码字符串
 */
static char *Bcd2Ascii(unsigned char *bcd, int len)
{
    // 定义常量以避免魔法数字
    const int charsPerByte = 2;  // 每个字节BCD码转换为2个ASCII字符
    const int terminatorLength = 1;  // 字符串终止符长度
    
    // 根据BCD码长度，分配足够的空间存储转换后的ASCII码字符串
    // 每个字节的BCD码转换为两位的ASCII码，因此需要len * charsPerByte个字符空间
    // 加上一个字符用于null终止符
    char *asc = new char[len * charsPerByte + terminatorLength];
    
    // 遍历每个BCD码字节，将其转换为两位的十六进制ASCII码表示
    for (int i = 0; i < len; i++) {
        // 使用sprintf_s函数将BCD码转换为十六进制字符串，存储在asc数组中
        // "%02x"格式化字符串确保每个字节转换为两位的十六进制表示，不足两位时前面补0
        int result = sprintf(&asc[i * charsPerByte], "%02x", bcd[i]);
        if (result < 0) {
            // 处理错误情况
            // ：可以记录错误日志或抛出异常
            // 这里假设简单地返回NULL表示转换失败
            return nullptr;
        }
    }
    // 返回转换后的ASCII码字符串首地址
    return asc;
}

void Init(int devid)
{
    // 定义常量以避免魔法数字
    const uint32_t deviceIdBusnumMask = 0xFFFF0000;    // 设备ID中总线号的掩码
    const uint32_t deviceIdDevnumMask = 0xFFFF;        // 设备ID中设备号的掩码
    const int busnumShiftBits = 16;                     // 总线号在设备ID中的位移位数
    const uint32_t handleShiftBits = 32;                // 设备句柄中总线号的位移位数
    const int defaultConfigIndex = 1;                   // 默认配置描述符索引
    
    g_deviceId = devid;
    LOG("printer init deviceid %{public}d", g_deviceId);
    int ret;
    // 初始化USB设备
    ret = OH_Usb_Init();
    LOG("OH_Usb_Init ret %{public}d", ret);
    // 获取设备描述符
    uint32_t busNum = ((g_deviceId & deviceIdBusnumMask) >> busnumShiftBits);
    uint32_t deviceNum = g_deviceId & deviceIdDevnumMask;
    g_devHandle = (static_cast<uint64_t>(busNum) << handleShiftBits) | deviceNum;
    // 获取设备描述信息
    ret = OH_Usb_GetDeviceDescriptor(g_devHandle, &devDesc);
    LOG("OH_Usb_GetDeviceDescriptor ret %{public}d %{public}d %{public}d", ret, devDesc.idProduct, devDesc.idVendor);
    struct UsbDdkConfigDescriptor *config = nullptr;
    // 获取配置描述符
    ret = OH_Usb_GetConfigDescriptor(g_devHandle, defaultConfigIndex, &config);
    LOG("OH_Usb_GetConfigDescriptor ret %{public}d", ret);
    // 解析接口和端点信息
    auto [res, interface, endpoint, maxPktSize] = GetInterfaceAndEndpoint(config, false);
    LOG("GetInterfaceAndEndpoint endpoint %{public}d", endpoint);
    LOG("GetInterfaceAndEndpoint interface %{public}d", interface);
    // 释放配置描述符资源
    OH_Usb_FreeConfigDescriptor(config);
    // 设置数据端点、最大包大小和接口
    g_dataEp = endpoint;
    g_maxPktSize = maxPktSize;
    g_interface = interface;
    // 占用接口，同时也会卸载内核键盘驱动
    ret = OH_Usb_ClaimInterface(g_devHandle, g_interface, &g_interfaceHandle);
}


/**
 * @brief 写身份识别卡
 * 该函数通过USB接口向设备发送命令，以写入身份识别卡。它首先检查输入值是否有效，
 * 然后创建设备内存映射，将命令数据复制到缓冲区，并通过USB管道请求发送数据。
 * @param value 要写入的命令值，应介于1到TX_ORDER_NUM之间
 * @return int 返回0表示成功，-1表示输入值无效
 */
int GkhIdentityCardWrite(int value)
{
    // 定义常量以避免魔法数字
    const int usbMemMapSize = 10;           // USB内存映射大小
    const int logBufferSize = 128;           // 日志缓冲区大小
    const int hexFormatWidth = 5;            // 十六进制格式化宽度
    const int dataPrintCount = 10;           // 打印数据的字节数
    const int usbTimeoutMs = 1000;           // USB操作超时时间(毫秒)
    
    g_readLen = 0;
    uint32_t bufferLen = g_maxPktSize;
    // 占用接口，同时也会卸载内核键盘驱动
    // 创建用于存放数据的缓冲区
    if (value < 1 || value > TX_ORDER_NUM) {
        LOG("Please specify :  1~7 \n");
        return -1;
    }
    UsbDeviceMemMap *devMmap = nullptr;
    g_cmd = value - 1;
    int length;
    int32_t ret = OH_Usb_CreateDeviceMemMap(g_devHandle, usbMemMapSize, &devMmap);
    length = sizeof(WRITE_BUF[g_cmd]);
    LOG("gkh_identity_card_write sizeof(WRITE_BUF[g_cmd]):%{public}d", length);
    memcpy(devMmap->address, WRITE_BUF[g_cmd], length); // 使用memcpy进行拷贝

    struct UsbRequestPipe pipe;
    pipe.interfaceHandle = g_interfaceHandle;
    // 根据配置描述符找到所要通信的端点
    pipe.endpoint = BULK_ENDPOINT_OUT;
    pipe.timeout = usbTimeoutMs;
    OH_Usb_SendPipeRequest(&pipe, devMmap);
    LOG("gkh_identity_card_write OH_Usb_SendPipeRequest ret:%{public}d", ret);

    char *str = (char *)malloc(logBufferSize);
    memset(str, 0, logBufferSize);
    unsigned char* a = devMmap->address;
    for (int i = 0; i < dataPrintCount; i++) {
            a++;
    }
    LOG("gkh_identity_card_write tranform length:%{public}d \n", devMmap->transferedLength);
    free(str);

    OH_Usb_DestroyDeviceMemMap(devMmap);
    LOG("OH_Usb_DestroyDeviceMemMap ");
    return 0;
}

/**
 * 创建设备内存映射并读取数据
 */
static int ReadDataFromDevice(UsbDeviceMemMap **devMmap)
{
    // 定义常量以避免魔法数字
    const int usbTimeoutMs = 1000;           // USB操作超时时间(毫秒)
    const int maxBufferSize = 2048;          // 最大缓冲区大小

    uint32_t bufferLen = g_maxPktSize;
    // 占用接口，同时也会卸载内核键盘驱动
    // 创建用于存放数据的缓冲区
    int length;
    UsbDeviceMemMap *devMmapPtr = nullptr;
    int32_t ret = OH_Usb_CreateDeviceMemMap(g_devHandle, sizeof(g_readBuf), &devMmapPtr);
    LOG("GkhIdentityCardRead OH_Usb_CreateDeviceMemMap ret:%{public}d", ret);
    
    struct UsbRequestPipe pipe;
    pipe.interfaceHandle = g_interfaceHandle;
    // 根据配置描述符找到所要通信的端点
    pipe.endpoint = BULK_ENDPOINT_IN;
    pipe.timeout = usbTimeoutMs;
    ret = OH_Usb_SendPipeRequest(&pipe, devMmapPtr);
    memcpy(g_readBuf, devMmapPtr->address, devMmapPtr->transferedLength);
    LOG("GkhIdentityCardRead OH_Usb_SendPipeRequest ret:%{public}d transform length %{public}d",
        ret, devMmapPtr->transferedLength);
    
    *devMmap = devMmapPtr;
    return ret;
}

/**
 * 记录读取数据的日志
 */
static void LogReadData(UsbDeviceMemMap *devMmap)
{
    // 定义常量以避免魔法数字
    const int logBufferSize = 128;           // 日志缓冲区大小
    const int hexFormatWidth = 5;            // 十六进制格式化宽度
    const int dataPrintCount = 10;           // 打印数据的字节数

    char *str = (char *)malloc(logBufferSize);
    memset(str, 0, logBufferSize);

    unsigned char *a = devMmap->address;
    for (int i = 0; i < dataPrintCount; i++) {
        a++;
    }
    free(str);
}

/**
 * 检查状态字节是否匹配特定条件
 */
static bool IsStatusMatch(int i)
{
    const int statusByteOffset = 9;                  // 状态字节偏移量
    const int readBufferIndex8 = 8;                 // 读取缓冲区索引8
    const int readBufferIndex7 = 7;                 // 读取缓冲区索引7
    const int swIndex0 = 0;                          // SW数组索引0
    const int swIndex1 = 1;                          // SW数组索引1
    const int swIndex2 = 2;                          // SW数组索引2
    
    return (g_readBuf[statusByteOffset] == SW[i][swIndex2]) &&
           (g_readBuf[readBufferIndex8] == SW[i][swIndex1]) &&
           (g_readBuf[readBufferIndex7] == SW[i][swIndex0]);
}

/**
 * 处理默认索引(0x00)的状态匹配
 */
static int HandleDefaultIndexMatch(int i)
{
    const int swIndex3 = 3;                          // SW数组索引3
    const unsigned char swIndex3Error = 0xff;       // SW数组索引3的错误标识
    const int errorReturnValue = -1;                 // 错误返回值
    
    if (SW[i][swIndex3] == swIndex3Error) {
        LOG("0x00 SW[i][3] == 0xff");
        return errorReturnValue;
    } else {
        LOG("0x00 status :0x%x \n", SW[i][swIndex3]);
        return SW[i][swIndex3];
    }
}

/**
 * 处理非默认索引的状态匹配
 */
static int HandleNonDefaultIndexMatch(int i)
{
    const int statusByteOffset = 9;                  // 状态字节偏移量
    const int swIndex2 = 2;                          // SW数组索引2
    const int swIndex3 = 3;                          // SW数组索引3
    const unsigned char swIndex3Error = 0xff;       // SW数组索引3的错误标识
    const int errorReturnValue = -1;                 // 错误返回值
    
    if (g_readBuf[statusByteOffset] != SW[i][swIndex2]) {
        return errorReturnValue; // 不匹配直接返回
    }
    
    if (SW[i][swIndex3] == swIndex3Error) {
        LOG("SW[i][3] == 0xff");
        return errorReturnValue;
    } else {
        LOG("status :0x%x \n", SW[i][swIndex3]);
        return SW[i][swIndex3];
    }
}

/**
 * 解析状态字节并返回对应状态
 */
static int ParseStatusBytes()
{
    // 定义常量以避免魔法数字
    const unsigned char swIndex0Default = 0x00;     // SW数组索引0的默认值
    const int errorReturnValue = -1;                 // 错误返回值
    const int swIndex0 = 0;                          // SW数组索引0

    int ret = errorReturnValue;
    for (int i = 0; i < RX_STATES_NUM; i++) {
        bool isMatch = IsStatusMatch(i);
        // 处理默认索引匹配的情况
        if (SW[i][swIndex0] == swIndex0Default && isMatch) {
            ret = HandleDefaultIndexMatch(i);
            break;
        } else if (isMatch) {
            ret = HandleNonDefaultIndexMatch(i);
            break;
        }
    }
    
    return ret;
}

/**
 * 复制数据到输出参数
 */
static void CopyDataToOutput(UsbDeviceMemMap *devMmap, unsigned char *data)
{
    const int minResponseLength = 11;        // 最小响应长度
    const int dataStartOffset = 10;          // 数据起始偏移量

    if (data != NULL && devMmap->transferedLength > minResponseLength) {
        memcpy(data,
               devMmap->address + dataStartOffset,
               devMmap->transferedLength - minResponseLength);
    }
}

/**
 * @brief 读取身份验证卡的数据
 * 本函数通过USB接口与设备通信，发送请求并接收设备返回的数据。
 * 它首先创建设备内存映射，然后发送管道请求以读取数据，并对读取的数据进行处理。
 * @param data 指向用于存储读取数据的缓冲区的指针
 * @return int 返回读取状态，-1表示读取失败，其他值表示读取成功
 */
int GkhIdentityCardRead(unsigned char * data)
{
    UsbDeviceMemMap *devMmap = nullptr;
    // 读取数据
    int ret = ReadDataFromDevice(&devMmap);
    if (ret < 0) {
        return -1;
    }
    // 记录日志
    LogReadData(devMmap);
    // 解析状态
    ret = ParseStatusBytes();
    // 复制数据
    CopyDataToOutput(devMmap, data);
    // 清理资源
    OH_Usb_DestroyDeviceMemMap(devMmap);
    LOG("GkhIdentityCardRead ret :%{public}d", ret);
    return ret;
}

/**
 * 关闭身份卡连接
 * 该函数用于关闭与身份卡的连接它首先检查设备句柄和接口句柄是否已初始化，
 * 如果未初始化，则记录错误信息并返回错误代码如果句柄有效，则尝试释放USB接口，
 * 并在完成后释放USB DDK资源
 * @return 返回执行结果，0表示成功，非0表示失败
 */
int GkhIdentityCardClose(void)
{
    // 定义常量以避免魔法数字
    const int errorCode = -1;        // 错误返回码
    int ret;
    // 检查设备句柄和接口句柄是否有效
    if (g_devHandle == 0 || g_interfaceHandle == 0) {
        LOG("g_devHandle:0 or g_interfaceHandle:0");
        return errorCode;
    }
    // 释放USB接口
    ret = OH_Usb_ReleaseInterface(g_interfaceHandle);
    // 释放USB DDK资源
    OH_Usb_Release();
    LOG("GkhIdentityCardClose OH_Usb_ReleaseInterface ret : %{public}d.", ret);
    return ret;
}

/**
 * 搜索身份证卡片函数
 * 本函数通过向卡片发送搜索指令来搜索身份证卡片的存在性
 * 首先，它会调用gkh_identity_card_write函数发送搜索指令（CMD_SEARCH）
 * 如果发送指令成功，它会尝试读取卡片的响应以确认搜索结果
 * @return 返回搜索结果或错误代码
 */
int IdCardSearch()
{
    // 定义常量以避免魔法数字
    const int errorThreshold = 0;  // 错误阈值，用于判断操作是否失败
    int ret;
    // 记录搜索卡片操作的日志
    LOG("IdCardSearch");
    // 向卡片发送搜索指令，并获取操作结果
    ret = GkhIdentityCardWrite(CMD_SEARCH);
    // 记录发送指令结果的日志
    LOG("IdCardSearch gkh_identity_card_write ret : %{public}d.", ret);
    // 如果发送指令失败（返回值小于errorThreshold），记录错误日志并返回错误代码
    if (ret < errorThreshold) {
        LOG("IdCardSearch <0");
        return ret;
    }
    // 尝试读取卡片响应，尽管在此函数中不处理具体响应数据
    // 这里传入NULL作为参数，表示不关心读取的数据内容
    ret = GkhIdentityCardRead(nullptr);

    // 记录读取操作结果的日志
    LOG("IdCardSearch GkhIdentityCardRead ret : %{public}d.", ret);

    // 返回读取操作的结果
    return ret;
}

/**
 * 选择身份卡功能的实现。
 * 本函数通过调用gkh_identity_card_write和gkh_identity_card_read函数来选择身份卡。
 * 首先，它发送一个选择命令到身份卡，然后读取身份卡的响应以确认选择操作的成功。
 * @return 返回选择操作的结果，如果操作成功，返回值应为非负数；如果操作失败，返回负数错误码。
 */
int IdCardSelect()
{
    // 定义常量以避免魔法数字
    const int errorThreshold = 0;  // 错误阈值，用于判断操作是否失败
    
    int ret;

    // 记录选择身份卡操作的开始
    LOG("IdCardSelect");

    // 向身份卡发送选择命令
    ret = GkhIdentityCardWrite(CMD_SELECT);

    // 记录发送选择命令后的返回值
    LOG("IdCardSelect gkh_identity_card_write ret : %{public}d.", ret);

    // 检查发送选择命令是否成功
    if (ret < errorThreshold) {
        // 如果发送失败，记录错误并返回错误码
        LOG("IdCardSelect < 0");
        return ret;
    }

    // 读取身份卡的响应，以确认选择操作的成功
    ret = GkhIdentityCardRead(nullptr);

    // 记录读取操作的返回值
    LOG("IdCardSelect GkhIdentityCardRead ret : %{public}d.", ret);

    // 返回选择操作的结果
    return ret;
}

/**
 * @brief 向身份证读卡器发送指令并接收信息
 * 本函数首先向身份证读卡器发送一个指令包，然后读取信息。
 * 如果发送指令成功，将返回读取的信息长度；如果发送指令失败，则返回错误码。
 * @param info 指向缓冲区的指针，用于存储读取的身份证信息
 * @return int 返回读取的信息长度或错误码
 */
int IdCardInfo(unsigned char* info)
{
    // 定义常量以避免魔法数字
    const int errorThreshold = 0;     // 错误阈值，用于判断操作是否失败
    const int noDataRead = 0;        // 无数据读取的标志值
    
    // 打印初始化设备ID和传入的信息
    LOG("printer init deviceid %{public}d", info);
    int ret;
    // 函数开始日志
    LOG("IdCardInfo");
    // 向身份证读卡器写入指令
    ret = GkhIdentityCardWrite(CMD_INFO);
    // 打印写入指令的返回结果
    LOG("IdCardInfo gkh_identity_card_write ret : %{public}d.", ret);
    // 如果写入指令失败
    if (ret < errorThreshold) {
        // 打印错误日志
        LOG("IdCardInfo < 0");
        // 返回错误码
        return ret;
    }
    // 从身份证读卡器读取信息
    ret = GkhIdentityCardRead(info);
    // 打印读取信息的返回结果和读取长度
    LOG("IdCardInfo GkhIdentityCardRead ret: %{public}d, g_readLen: %{public}d", ret, g_readLen);
    // 如果读取到信息
    if (g_readLen != noDataRead) {
        // 返回读取长度
        return g_readLen;
    } else {
        // 否则返回错误码
        return ret;
    }
}

/**
 * 获取卡片信息
 * 此函数通过调用idc_card_info函数来获取卡片信息，并将其格式化为字符串返回
 * 它首先尝试读取卡片信息，然后根据返回值和读取到的数据生成一个字符串
 * 如果卡片信息读取成功，它会将部分信息日志记录，并将格式化后的信息返回
 * @return 返回卡片信息的字符串表示，如果获取失败则返回空字符串
 */
std::string FetchCardInfo()
{
    // 定义常量以避免魔法数字
    const int infoBufferSize = 2048;        // 信息缓冲区大小
    const int logStrSize = 224;             // 日志字符串缓冲区大小
    const int hexFormatWidth = 5;           // 十六进制格式化宽度
    const int dataPrintCount = 10;          // 打印数据的字节数
    const int resultBufferSize = 512;       // 结果缓冲区大小
    const int successThreshold = 0;          // 成功阈值，用于判断操作是否成功
    
    // 日志记录函数调用开始
    LOG("FetchCardInfo");
    
    // 初始化结果字符串为空
    std::string result = "";
    
    // 准备一个缓冲区用于存储卡片信息
    unsigned char infobuf[infoBufferSize] = {0};
    
    // 调用idc_card_info函数获取卡片信息，ret用于指示操作是否成功
    int ret = IdCardInfo(infobuf);

    // 分配一个字符串缓冲区用于构建卡片信息的可读格式
    char *str = (char *)malloc(logStrSize);
    memset(str, 0, logStrSize);
    
    // 将infobuf的起始地址赋给a，用于后续遍历
    unsigned char *a = infobuf;
    
    // 遍历infobuf的前dataPrintCount个字节，将它们格式化为十六进制字符串
    for (int i = 0; i < dataPrintCount; i++) {
        a++;
    }
    
    // 如果卡片信息获取成功
    if (ret > successThreshold) {
        // 准备一个缓冲区用于存储格式化后的卡片信息
        char buf[resultBufferSize] = {0};
        int validLen = logStrSize;
        
        int results = sprintf(buf, "%s", Bcd2Ascii(infobuf, validLen));
        if (results < 0) {
        // 处理错误情况
        LOG("sprintf failed with error code: %{public}d", results);
        // 可以选择返回空字符串或采取其他错误处理措施
        buf[0] = '\0'; // 确保buf是空字符串
        }
        // 日志记录格式化后的卡片信息
        LOG("FetchCardInfo buf: %{public}s.", buf);
        // 将格式化后的卡片信息添加到结果字符串中
        result += buf;
    }
    // 日志记录最终的卡片信息结果
    LOG("FetchCardInfo result:  %{public}s.", result.c_str());
    // 返回卡片信息的字符串表示
    return result;
}

// 自检
void SelfCheck()
{
    // 定义常量以避免魔法数字
    const int selfCheckCmdSize = 7;              // 自检命令数据大小
    const unsigned char cmdByte1 = 0x1D;          // 命令字节1
    const unsigned char cmdByte2 = 0x28;          // 命令字节2
    const unsigned char cmdByte3 = 0x41;          // 命令字节3
    const unsigned char cmdByte4 = 0x02;          // 命令字节4
    const unsigned char cmdByte5 = 0x00;          // 命令字节5
    const unsigned char cmdByte6 = 0x00;          // 命令字节6
    const unsigned char cmdByte7 = 0x02;          // 命令字节7
    
    char bsend[selfCheckCmdSize];
    int iIndex = 0;
    bsend[iIndex++] = cmdByte1;
    bsend[iIndex++] = cmdByte2;
    bsend[iIndex++] = cmdByte3;
    bsend[iIndex++] = cmdByte4;
    bsend[iIndex++] = cmdByte5;
    bsend[iIndex++] = cmdByte6;
    bsend[iIndex++] = cmdByte7;
    LOG("SelfCheck data size %{public}d", sizeof(bsend));
}

std::string SayHello(std::string msg)
{
    LOG("SayHello sayhello %{public}s", msg.c_str());
    return msg + " too.";
}

JSBIND_ADDON(printer);

// Step 2 注册 FFI 特性
JSBIND_GLOBAL()
{
    JSBIND_FUNCTION(Init);
    JSBIND_FUNCTION(SayHello);
    JSBIND_FUNCTION(SelfCheck);
    JSBIND_FUNCTION(IdCardSearch);
    JSBIND_FUNCTION(IdCardSelect);
    JSBIND_FUNCTION(FetchCardInfo);
    JSBIND_FUNCTION(GkhIdentityCardClose);
}